export type CRCAlgorithm = 'CRC8' | 'CRC16' | 'CRC32' | 'CRC16-CCITT';

export interface CRCChecker {
  calculate: (data: ArrayBuffer) => number;
  verify: (data: ArrayBuffer, checksum: number) => boolean;
  generatePacket: (data: ArrayBuffer) => ArrayBuffer;
  validatePacket: (packet: ArrayBuffer) => { data: ArrayBuffer; valid: boolean };
}

export function createCRCChecker(algorithm: CRCAlgorithm = 'CRC16-CCITT'): CRCChecker {
  const crcTable: number[] = [];

  // 初始化CRC表（以CRC16-CCITT为例）
  const initCRCTable = (_algorithm: CRCAlgorithm) => {
    let poly = 0x07;
    switch (_algorithm) {
      case 'CRC8':
        poly = 0x07;
        for (let i = 0; i < 256; i++) {
          let crc = i;
          for (let j = 0; j < 8; j++) {
            crc = crc & 0x80 ? (crc << 1) ^ poly : crc << 1;
          }
          crcTable[i] = crc & 0xff;
        }
      case 'CRC16':
        poly = 0xa001;
        for (let i = 0; i < 256; i++) {
          let crc = i;
          for (let j = 0; j < 8; j++) {
            crc = crc & 1 ? (crc >>> 1) ^ poly : crc >>> 1;
          }
          crcTable[i] = crc >>> 0;
        }
        break;
      case 'CRC32':
        poly = 0xedb88320;
        for (let i = 0; i < 256; i++) {
          let crc = i;
          for (let j = 0; j < 8; j++) {
            crc = crc & 1 ? (crc >>> 1) ^ poly : crc >>> 1;
          }
          crcTable[i] = crc >>> 0;
        }
        break;
      case 'CRC16-CCITT':
        poly = 0x1021;
        for (let i = 0; i < 256; i++) {
          let crc = i << 8;
          for (let j = 0; j < 8; j++) {
            crc = crc & 0x8000 ? (crc << 1) ^ poly : crc << 1;
          }
          crcTable[i] = crc & 0xffff;
        }
    }
  };

  // 计算CRC校验码
  const calculateCRC = (data: ArrayBuffer): number => {
    const view = new DataView(data);
    let crc = 0xffff;

    for (let i = 0; i < data.byteLength; i++) {
      const byte = view.getUint8(i);
      const index = ((crc >> 8) ^ byte) & 0xff;
      crc = (crc << 8) ^ crcTable[index];
      crc &= 0xffff;
    }

    return crc;
  };

  // 初始化CRC表
  initCRCTable(algorithm);

  return {
    calculate(data) {
      return calculateCRC(data);
    },

    verify(data, checksum) {
      return calculateCRC(data) === checksum;
    },

    generatePacket(data) {
      const crc = calculateCRC(data);
      const packet = new ArrayBuffer(data.byteLength + 2);
      const view = new DataView(packet);

      // 复制原始数据
      new Uint8Array(packet).set(new Uint8Array(data), 0);

      // 追加CRC校验码（大端序）
      view.setUint16(data.byteLength, crc, false);
      return packet;
    },

    validatePacket(packet) {
      if (packet.byteLength < 2) {
        throw new Error('Invalid packet length');
      }

      const dataLength = packet.byteLength - 2;
      const data = packet.slice(0, dataLength);
      const receivedChecksum = new DataView(packet).getUint16(dataLength, false);

      return {
        data,
        valid: calculateCRC(data) === receivedChecksum
      };
    }
  };
}
